﻿#ifndef MATRIX_H
#define MATRIX_H

//include定義
#include "Common.h"
#include "Maths.h"

class Matrix
{

public:
	//コンストラクタ
	Matrix();
	Matrix(const mat4 &p_matrix);

	//デストラクタ
	~Matrix();

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　演算子のオーバーロード定義
	*-------------------------------------------------------------------------------*/
	friend Matrix operator*(const Matrix &p_left, const Matrix &p_right);
	friend Matrix operator*(const Matrix &p_left, const mat4 &p_right);
	friend Matrix operator*(const mat4 &p_left, const Matrix &p_right);
	friend Matrix operator*(const mat4 &p_left, const mat4 &p_right);
	void operator=(const mat4 &p_matrix);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　単位行列を生成する
	*	引数
	*	　なし
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Identity();

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　移動行列を適応する
	*	引数
	*	　p_x	：[I/ ]　X 座標の移動量
	*	　p_y	：[I/ ]　Y 座標の移動量
	*	　p_z	：[I/ ]　Z 座標の移動量
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Translate(const GLfloat p_x, const GLfloat p_y, const GLfloat p_z);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　拡大/縮小行列を適応する
	*	引数
	*	　p_x	：[I/ ]　X 座標の倍率
	*	　p_y	：[I/ ]　Y 座標の倍率
	*	　p_z	：[I/ ]　Z 座標の倍率
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Scale(const GLfloat p_x, const GLfloat p_y, const GLfloat p_z);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　回転行列を適応する
	*	引数
	*	　p_rotate	：[I/ ]　回転角度（360度系）
	*	　下記、回転軸となる正規化された方向ベクトルを設定する
	*	　p_x		：[I/ ]　回転軸 X 成分（例：X 成分だけに効かせる場合は 1.0 を指定、その他 0.0）
	*	　p_y		：[I/ ]　回転軸 Y 成分（例：Y 成分だけに効かせる場合は 1.0 を指定、その他 0.0）
	*	　p_z		：[I/ ]　回転軸 Z 成分（例：Z 成分だけに効かせる場合は 1.0 を指定、その他 0.0）
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Rotate(const GLfloat p_rotate, const GLfloat p_x, const GLfloat p_y, const GLfloat p_z);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　視野変換行列を適応する
	*	引数
	*	　p_eye		：[I/ ]　カメラの位置
	*	　p_look	：[I/ ]　カメラの注視点
	*	　p_up		：[I/ ]　カメラの上向きベクトル
	*				  （例：Y 成分が上下成分で、上が上向きの場合は、Y だけ 1.0、その他は 0.0 を指定）
	*
	*	　図は下記URLの「視野変換行列」項目参照
	*	　http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20090902
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void LookAt(const vec3 &p_eye, const vec3 &p_look, const vec3 &p_up);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　平行投影変換行列を適応する
	*	引数
	*	　p_left	：[I/ ]　近くの面(p_near面)の左側までの距離
	*	　p_right	：[I/ ]　近くの面(p_near面)の右側までの距離
	*	　p_bottom	：[I/ ]　近くの面(p_near面)の下側までの距離
	*	　p_top		：[I/ ]　近くの面(p_near面)の上側までの距離
	*	　p_near	：[I/ ]　近くの面までの距離
	*	　p_far		：[I/ ]　遠くの面までの距離
	*
	*	　図は下記URLの「平行投影変換」項目参照
	*	　http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20090829
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Orthogonal(const GLfloat p_left, const GLfloat p_right,
					const GLfloat p_bottom, const GLfloat p_top,
					const GLfloat p_near, const GLfloat p_far);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　透視投影変換行列を適応する
	*	　一つ下にある「Perspective」関数でも行列を作成することが可能です（オーバーロードしてあります）
	*	　引数が違うので、使いやすい方や用途に合わせて使用すること（結果的には同じことができます）
	*	引数
	*	　p_left	：[I/ ]　近くの面(p_near面)の左側までの距離
	*	　p_right	：[I/ ]　近くの面(p_near面)の右側までの距離
	*	　p_bottom	：[I/ ]　近くの面(p_near面)の下側までの距離
	*	　p_top		：[I/ ]　近くの面(p_near面)の上側までの距離
	*	　p_near	：[I/ ]　近くの面までの距離
	*	　p_far		：[I/ ]　遠くの面までの距離
	*
	*	　図は下記URLの「透視投影変換」項目参照
	*	　http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20090829
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Perspective(const GLfloat p_left, const GLfloat p_right,
					 const GLfloat p_bottom, const GLfloat p_top,
					 const GLfloat p_near, const GLfloat p_far);
	
	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　透視投影変換行列を適応する
	*	　一つ上にある「Perspective」関数でも行列を作成することが可能です（オーバーロードしてあります）
	*	　引数が違うので、使いやすい方や用途に合わせて使用すること（結果的には同じことができます）
	*	引数
	*	　p_near		：[I/ ]　近くの面までの距離
	*	　p_far			：[I/ ]　遠くの面までの距離
	*	　p_fovY_deg	：[I/ ]　カメラの Y方向の画角
	*	　p_aspect		：[I/ ]　描画先の画面のアスペクト比（幅 ÷ 高さ）
	*
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Perspective(const GLfloat p_near, const GLfloat p_far,
					 const GLfloat p_fovY_degree, const GLfloat p_aspect);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　逆行列を求める
	*	　参考サイト：http://thira.plavox.info/blog/2008/06/_c.html
	*	引数
	*	　なし
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Inverse(void);

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　転置行列を求める
	*	引数
	*	　なし
	*	戻り値
	*	　なし
	*-------------------------------------------------------------------------------*/
	void Transpose(void);
	
	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　行列の値を取得する
	*	引数
	*	　なし
	*	戻り値
	*	　行列の値
	*-------------------------------------------------------------------------------*/
	inline mat4 GetMatrix()
	{
		//メンバに保存されているマトリックスを返却
		return m_val;
	}

	/*-------------------------------------------------------------------------------
	*	関数説明
	*	　行列の値を取得する（GLfloat型）
	*	　※「glUniformMatrix4fv」などでマトリクスを設定するときに使用する。
	*　　　　単に値を取得したいだけであれば「GetMatrix」の方を使ってください。
	*	引数
	*	　なし
	*	戻り値
	*	　行列の値（GLfloat型）
	*-------------------------------------------------------------------------------*/
	inline const GLfloat* GetMatrixFloat()
	{
		//メンバに保存されているマトリックスを返却
		return (GLfloat*)&m_val;
	}


private:

	// 行列用の配列
	//
	// [0][0] [0][1] [0][2] [0][3]
	// [1][0] [1][1] [1][2] [1][3]
	// [2][0] [2][1] [2][2] [2][3]
	// [3][0] [3][1] [3][2] [3][3]
	//
	mat4 m_val;
};
#endif